package scalab.tasks

import java.net.{URL, URLClassLoader}
import java.lang.reflect.{Constructor, Method}

/**
* This task dynamically loads a task (received on its loadPath input) and runs it.
*/

trait DynamicTask extends JVMComponent{

	//todo: forward classpath and bootclasspath...

	val loadPath = mandatoryIn//classes to be loaded arrive here
	def getLoadPath: Array[URL] = (loadPath.sources map {d => d.toURL}).toList.toArray

	var classLoader: ClassLoader = _
	def createClassLoader: Unit = {
		classLoader = new java.net.URLClassLoader(getLoadPath, null)
	}

	//todo: take mainclass as input and translate fileName => binaryname
	val binaryClassName: String//binary class of main class (having main method)

	def loadTaskClass: Class[T] forSome {type T} = {
		classLoader.loadClass(binaryClassName)
	}

	var taskInstance: AnyRef = _
	def createTaskInstance: Unit = {
		taskInstance = loadTaskClass.newInstance.asInstanceOf[AnyRef]
	}
	def createTaskInstance(constructor: Constructor[T] forSome {type T}, constructorParams: Array[AnyRef]): Unit = {
		taskInstance = constructor.newInstance(constructorParams).asInstanceOf[AnyRef]
	}
	def createTaskInstance(constructorTypes: Array[Class[T] forSome {type T}], constructorParams: Array[AnyRef]): Unit = {
		val constructor = loadTaskClass.getConstructor(constructorTypes)
		taskInstance = constructor.newInstance(constructorParams).asInstanceOf[AnyRef]
	}

	def invoke(methodName: String, methodTypes: Array[Class[T] forSome {type T}] , methodParams: Array[AnyRef]) = 
		taskInstance.getClass.getMethod(methodName, methodTypes).invoke(taskInstance, methodParams)
}
